<?php

namespace app\admin\controller\scanwork;

use app\common\controller\Backend;
use app\admin\model\scanwork\TraceCode as TraceCodeModel;
use app\admin\model\scanwork\Config as ConfigModel;
use app\admin\model\scanwork\Report;
use app\admin\model\scanwork\Allocation;
use app\admin\model\scanwork\Product;
use app\admin\model\scanwork\Process;
use app\admin\model\scanwork\ProductModel;
use think\Db;
use think\Exception;

/**
 * 追溯码管理
 */
class TraceCode extends Backend
{
    protected $model = null;
    protected $noNeedRight = ['index', 'getTraceInfo', 'downloadQrCode', 'generate', 'generateAll', 'preview', 'detail'];
    protected $dataLimit = false; // 关闭数据权限限制

    public function _initialize()
    {
        parent::_initialize();
        $this->model = new TraceCodeModel;
    }

    /**
     * 查看
     */
    public function index()
    {
        if ($this->request->isAjax()) {
            list($where, $sort, $order, $offset, $limit) = $this->buildparams();

            // 关联查询获取完整的报工信息
            $list = $this->model
                ->alias('t')
                ->join('fa_scanwork_report r', 't.report_id = r.id')
                ->join('fa_scanwork_allocation a', 'r.allocation_id = a.id')
                ->join('fa_scanwork_order o', 'a.order_id = o.id')
                ->join('fa_scanwork_model m', 'a.model_id = m.id')
                ->join('fa_scanwork_process p', 'a.process_id = p.id')
                ->join('fa_user worker', 'r.user_id = worker.id', 'LEFT')
                ->join('fa_user auditor', 'r.audit_user_id = auditor.id', 'LEFT')
                ->field('t.*, o.order_no, m.name as model_name, m.model_code, p.name as process_name, worker.nickname as worker_name, auditor.nickname as auditor_name, r.quantity, r.item_nos, r.remark, r.audit_time as report_audit_time, r.audit_reason')
                ->order($sort ?: 't.id', $order ?: 'desc')
                ->paginate($limit ?: 10);

            $result = array("total" => $list->total(), "rows" => $list->items());

            return json($result, JSON_UNESCAPED_UNICODE);
        }
        return $this->view->fetch();
    }



    /**
     * 删除
     */
    public function del($ids = "")
    {
        if (!$this->request->isPost()) {
            $this->error(__("Invalid parameters"));
        }
        $ids = $ids ? $ids : $this->request->post("ids");
        if ($ids) {
            $pk = $this->model->getPk();
            $adminIds = $this->getDataLimitAdminIds();
            if (is_array($adminIds)) {
                $this->model->where($this->dataLimitField, 'in', $adminIds);
            }
            $list = $this->model->where($pk, 'in', $ids)->select();

            $count = 0;
            Db::startTrans();
            try {
                foreach ($list as $item) {
                    $count += $item->delete();
                }
                Db::commit();
            } catch (\think\exception\PDOException $e) {
                Db::rollback();
                $this->error($e->getMessage());
            } catch (\think\Exception $e) {
                Db::rollback();
                $this->error($e->getMessage());
            }
            if ($count) {
                $this->success();
            } else {
                $this->error(__('No rows were deleted'));
            }
        }
        $this->error(__('Parameter %s can not be empty', 'ids'));
    }

    /**
     * 生成追溯码
     */
    public function generate($ids = null)
    {
        if (!$ids) {
            $this->error('请选择要生成追溯码的报工记录');
        }

        $reportIds = explode(',', $ids);
        $successCount = 0;
        $errorCount = 0;

        Db::startTrans();
        try {
            foreach ($reportIds as $reportId) {
                // 检查是否已存在追溯码
                $existingTrace = TraceCodeModel::getTraceByReportId($reportId);
                if ($existingTrace) {
                    $errorCount++;
                    continue;
                }

                // 获取报工记录信息
                $report = Report::with(['allocation', 'allocation.model.product', 'allocation.process', 'user'])
                    ->where('id', $reportId)
                    ->find();

                if (!$report) {
                    $errorCount++;
                    continue;
                }

                // 准备追溯数据
                $traceData = [
                    'product_name' => $report->allocation->model && $report->allocation->model->product ? $report->allocation->model->product->name : '',
                    'item_no' => $report->allocation->model ? $report->allocation->model->name : '',
                    'process_name' => $report->allocation->process ? $report->allocation->process->name : '',
                    'worker_name' => $report->user ? $report->user->nickname : '',
                    'auditor_name' => $this->auth->nickname ?? '',
                    'remark' => $report->remark ?? '',
                    'audit_time' => $report->audit_time ?? time()
                ];

                // 创建追溯记录
                $traceCode = TraceCodeModel::createTraceCode($reportId, $traceData);
                if ($traceCode) {
                    $successCount++;
                    
                    // 生成溯源码二维码图片
                    $qrImagePath = TraceCodeModel::generateQrCodeImage($traceCode->trace_code);
                    if ($qrImagePath) {
                        \think\Log::info("溯源码二维码生成成功 - 溯源码: {$traceCode->trace_code}, 图片路径: {$qrImagePath}");
                    }
                } else {
                    $errorCount++;
                }
            }

            Db::commit();
            $this->success("成功生成 {$successCount} 个追溯码，失败 {$errorCount} 个");
        } catch (\Exception $e) {
            Db::rollback();
            $this->error('生成追溯码失败：' . $e->getMessage());
        }
    }

    /**
     * 批量生成所有历史报工记录的追溯码
     */
    public function generateAll()
    {
        // 获取所有已审核但未生成追溯码的报工记录
        $reports = Report::with(['allocation', 'allocation.model.product', 'allocation.process', 'user'])
            ->where('status', 1) // 已审核的报工记录
            ->select();

        $successCount = 0;
        $errorCount = 0;
        $skipCount = 0;

        Db::startTrans();
        try {
            foreach ($reports as $report) {
                // 检查是否已存在追溯码
                $existingTrace = TraceCodeModel::getTraceByReportId($report->id);
                if ($existingTrace) {
                    $skipCount++;
                    continue;
                }

                // 准备追溯数据
                $traceData = [
                    'product_name' => $report->allocation->model && $report->allocation->model->product ? $report->allocation->model->product->name : '',
                    'item_no' => $report->allocation->model ? $report->allocation->model->name : '',
                    'process_name' => $report->allocation->process ? $report->allocation->process->name : '',
                    'worker_name' => $report->user ? $report->user->nickname : '',
                    'auditor_name' => $this->auth->nickname ?? '',
                    'remark' => $report->remark ?? '',
                    'audit_time' => $report->audit_time ?? time()
                ];

                // 创建追溯记录
                $traceCode = TraceCodeModel::createTraceCode($report->id, $traceData);
                if ($traceCode) {
                    $successCount++;
                    
                    // 生成溯源码二维码图片
                    $qrImagePath = TraceCodeModel::generateQrCodeImage($traceCode->trace_code);
                    if ($qrImagePath) {
                        \think\Log::info("溯源码二维码生成成功 - 溯源码: {$traceCode->trace_code}, 图片路径: {$qrImagePath}");
                    }
                } else {
                    $errorCount++;
                }
            }

            Db::commit();
            $this->success("批量生成完成！成功生成 {$successCount} 个追溯码，跳过 {$skipCount} 个（已存在），失败 {$errorCount} 个");
        } catch (\Exception $e) {
            Db::rollback();
            $this->error('批量生成追溯码失败：' . $e->getMessage());
        }
    }

    /**
     * 下载二维码
     */
    public function downloadQrCode($ids = null)
    {
        if (!$ids) {
            $this->error('请选择要下载的追溯码');
        }

        $traceIds = explode(',', $ids);
        $traceCodes = $this->model->where('id', 'in', $traceIds)->select();

        if (empty($traceCodes)) {
            $this->error('未找到追溯码记录');
        }

        // 生成二维码并打包下载
        $zipFile = $this->generateQrCodeZip($traceCodes);
        
        if ($zipFile && file_exists($zipFile)) {
            header('Content-Type: application/zip');
            header('Content-Disposition: attachment; filename="trace_codes_' . date('YmdHis') . '.zip"');
            header('Content-Length: ' . filesize($zipFile));
            readfile($zipFile);
            unlink($zipFile); // 删除临时文件
            exit;
        } else {
            $this->error('生成二维码文件失败');
        }
    }

    /**
     * 生成A4打印页面
     */
    public function printA4($ids = null)
    {
        // 从GET参数获取ids
        $ids = $this->request->get('ids');
        if (!$ids) {
            $this->error('请选择要打印的追溯码');
        }

        $traceIds = explode(',', $ids);
        $traceCodes = $this->model->where('id', 'in', $traceIds)->select();

        if (empty($traceCodes)) {
            $this->error('未找到追溯码记录');
        }

        // 生成A4打印页面
        $htmlContent = $this->generateA4PrintPage($traceCodes);
        
        // 输出HTML内容
        header('Content-Type: text/html; charset=utf-8');
        header('Content-Disposition: inline; filename="trace_codes_print_' . date('YmdHis') . '.html"');
        echo $htmlContent;
        exit;
    }

    /**
     * 生成A4打印页面HTML
     */
    private function generateA4PrintPage($traceCodes)
    {
        $html = '<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>追溯码打印页面</title>
    <style>
        @media print {
            @page {
                size: A4;
                margin: 0.5cm;
            }
            body {
                margin: 0 !important;
                padding: 0 !important;
                width: 100% !important;
            }
            .no-print {
                display: none !important;
            }
            .qr-grid {
                grid-template-columns: repeat(4, 1fr) !important;
                gap: 6px !important;
                margin-bottom: 8px !important;
            }
            .qr-card {
                width: 100% !important;
                padding: 6px !important;
                margin: 0 !important;
                min-height: 100px !important;
                box-shadow: none !important;
                border: 1px solid #ccc !important;
                border-radius: 4px !important;
            }
            .print-header {
                margin-bottom: 8px !important;
                padding: 6px !important;
            }
            .print-header h1 {
                font-size: 16px !important;
                margin-bottom: 4px !important;
            }
            .print-header p {
                font-size: 10px !important;
            }
            .qr-code-area {
                flex: 0 0 65px !important;
                padding: 4px !important;
                margin-right: 8px !important;
            }
            .qr-code-area img {
                width: 55px !important;
                height: 55px !important;
                margin-bottom: 4px !important;
            }
            .trace-code {
                font-size: 10px !important;
                padding: 3px 5px !important;
                letter-spacing: 0.3px !important;
                background: transparent !important;
                color: #000000 !important;
                border: 1px solid #000000 !important;
            }
            .info-title {
                font-size: 10px !important;
                margin-bottom: 4px !important;
                padding: 2px 4px !important;
            }
            .info-label,
            .info-value {
                font-size: 8px !important;
            }
            .info-grid {
                gap: 1px !important;
            }
            .info-item {
                padding: 1px 0 !important;
            }
        }
        
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: "Microsoft YaHei", "PingFang SC", sans-serif;
            background: #f5f5f5;
            padding: 15px;
        }
        
        .print-header {
            text-align: center;
            margin-bottom: 15px;
            padding: 10px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border-radius: 6px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.1);
        }
        
        .print-header h1 {
            font-size: 18px;
            margin-bottom: 5px;
        }
        
        .print-header p {
            font-size: 12px;
            opacity: 0.9;
        }
        
        .qr-grid {
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            gap: 10px;
            margin-bottom: 15px;
            width: 100%;
        }
        
        .qr-card {
            background: white;
            border-radius: 6px;
            padding: 10px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.08);
            border: 1px solid #eee;
            page-break-inside: avoid;
            min-height: 120px;
            display: flex;
            align-items: center;
            transition: all 0.3s ease;
        }
        

        
        .qr-code-area {
            flex: 0 0 70px;
            display: flex;
            flex-direction: column;
            align-items: center;
            padding: 5px;
            margin-right: 10px;
            background: #f8fafc;
            border-radius: 4px;
            border: 1px solid #e2e8f0;
        }
        
        .info-section {
            flex: 1;
            padding: 5px;
        }
        
        .qr-placeholder {
            width: 50px;
            height: 50px;
            margin: 0 auto;
            background: white;
            border: 1px solid #3b82f6;
            border-radius: 1px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: #3b82f6;
            font-weight: bold;
        }
        
        .trace-code {
            text-align: center;
            padding: 4px 6px;
            background: #f8f9fa;
            border-radius: 4px;
            font-family: monospace;
            font-size: 11px;
            font-weight: bold;
            color: #000000;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            width: 100%;
            letter-spacing: 0.5px;
            border: 1px solid #dee2e6;
        }
        
        .info-section {
            margin-top: 0.5px;
        }
        
        .info-title {
            font-size: 11px;
            font-weight: bold;
            color: #374151;
            margin-bottom: 5px;
            padding: 2px 5px;
            background: #f3f4f6;
            border-radius: 2px;
            text-align: center;
        }
        
        .info-grid {
            display: grid;
            grid-template-columns: 1fr;
            gap: 2px;
        }
        
        .info-item {
            display: flex;
            align-items: center;
            padding: 1px 0;
        }
        
        .info-label {
            font-size: 9px;
            color: #6b7280;
            font-weight: 600;
            min-width: 30px;
            margin-right: 5px;
        }
        
        .info-value {
            font-size: 9px;
            color: #1e2937;
            flex: 1;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }
        
        .print-actions {
            position: fixed;
            top: 20px;
            right: 20px;
            z-index: 1000;
        }
        
        .print-btn {
            background: #3b82f6;
            color: white;
            border: none;
            padding: 12px 24px;
            border-radius: 8px;
            cursor: pointer;
            font-size: 16px;
            font-weight: 500;
            box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
            transition: all 0.3s ease;
        }
        
        .print-btn:hover {
            background: #2563eb;
            transform: translateY(-2px);
        }
        
        .qr-code-area img {
            width: 70px;
            height: 70px;
            object-fit: contain;
            margin-bottom: 5px;
        }
        
        .page-break {
            page-break-before: always;
        }
        
        @media (max-width: 768px) {
            .qr-grid {
                grid-template-columns: 1fr;
            }
        }
    </style>
</head>
<body>
    <div class="print-actions no-print">
        <button class="print-btn" onclick="window.print()">
            🖨️ 打印页面
        </button>
    </div>
    
    <div class="print-header">
        <h1>🔍 产品追溯码打印</h1>
        <p>生成时间：' . date('Y-m-d H:i:s') . ' | 共 ' . count($traceCodes) . ' 个追溯码</p>
    </div>
    
    <div class="qr-grid">';

        foreach ($traceCodes as $index => $trace) {
            // 获取追溯码详细信息
            $traceData = $this->getTraceDetailData($trace->id);
            
            // 生成追溯页面URL
            $content = ConfigModel::getSiteDomain() . '/trace.html?id=' . $trace->trace_code;
            
            // 每32个追溯码分页（4列 x 8行）
            $numIndex = (int)$index;
            if ($numIndex > 0 && $numIndex % 32 == 0) {
                $html .= '<div class="page-break"></div>';
            }
            
            // 生成产品编号
            $productNumber = '';

            if (!empty($traceData['model_name'])) {
                $productNumber .= '' . $traceData['model_name'];
            }
            if (!empty($traceData['process_name'])) {
                $productNumber .= '-' . $traceData['process_name'];
            }
            // 添加其他信息（如果有的话）

            if (!empty($traceData['worker_name'])) {
                $productNumber .= '-' . $traceData['worker_name'];
            }
            
            // 检查二维码文件是否已存在
            $qrCodeFile = $this->getQrCodeFilePath($trace->trace_code);
            $qrCodeImageData = '';
            
            if (file_exists($qrCodeFile)) {
                // 文件存在，直接读取
                $qrCodeImageData = base64_encode(file_get_contents($qrCodeFile));
                \think\Log::info('使用已存在的二维码文件: ' . $trace->trace_code);
            } else {
                // 文件不存在，生成新的
                $this->generateQrCodeImage($content, $trace->trace_code, $traceData);
                $qrCodeImageData = base64_encode(file_get_contents($qrCodeFile));
                \think\Log::info('生成新的二维码文件: ' . $trace->trace_code);
            }
            
                        $html .= '
        <div class="qr-card">

            
            <div class="qr-code-area">
                <img src="data:image/png;base64,' . $qrCodeImageData . '" 
                     alt="追溯码二维码" 
                    >
            
            <div class="trace-code">' . $trace->trace_code . '</div>
            
                     </div>
            
           
            
            <div class="info-section">
                <div class="info-title">📋 产品信息</div>
                <div class="info-grid">';
            
            // 添加产品信息
            if (!empty($traceData['product_name'])) {
                $html .= '
                    <div class="info-item">
                        <span class="info-label">产品:</span>
                        <span class="info-value">' . htmlspecialchars($traceData['product_name']) . '</span>
                    </div>';
            }
            
            if (!empty($traceData['model_name'])) {
                $html .= '
                    <div class="info-item">
                        <span class="info-label">型号:</span>
                        <span class="info-value">' . htmlspecialchars($traceData['model_name']) . '</span>
                    </div>';
            }
            
            if (!empty($traceData['order_name'])) {
                $html .= '
                    <div class="info-item">
                        <span class="info-label">订单名称:</span>
                        <span class="info-value">' . htmlspecialchars($traceData['order_name']) . '</span>
                    </div>';
            }
            
            if (!empty($traceData['process_name'])) {
                $html .= '
                    <div class="info-item">
                        <span class="info-label">工序:</span>
                        <span class="info-value">' . htmlspecialchars($traceData['process_name']) . '</span>
                    </div>';
            }
            
            if (!empty($traceData['worker_name'])) {
                $html .= '
                    <div class="info-item">
                        <span class="info-label">员工:</span>
                        <span class="info-value">' . htmlspecialchars($traceData['worker_name']) . '</span>
                    </div>';
            }
            
            if (!empty($traceData['fabric_color'])) {
                $html .= '
                    <div class="info-item">
                        <span class="info-label">布料规格:</span>
                        <span class="info-value">' . htmlspecialchars($traceData['fabric_color']) . '</span>
                    </div>';
            }
            
            // 优先使用追溯码的审核时间，如果没有则使用报工记录的审核时间
            if (!empty($traceData['audit_time'])) {
                $auditTime = date('Y-m-d', $traceData['audit_time']);
                $html .= '
                    <div class="info-item">
                        <span class="info-label">时间:</span>
                        <span class="info-value">' . $auditTime . '</span>
                    </div>';
            } elseif (!empty($traceData['report_audit_time'])) {
                $auditTime = date('Y-m-d', $traceData['report_audit_time']);
                $html .= '
                    <div class="info-item">
                        <span class="info-label">时间:</span>
                        <span class="info-value">' . $auditTime . '</span>
                    </div>';
            } else {
                // 如果都没有审核时间，显示创建时间
                if (!empty($traceData['createtime'])) {
                    $createTime = date('Y-m-d', $traceData['createtime']);
                    $html .= '
                        <div class="info-item">
                            <span class="info-label">时间:</span>
                            <span class="info-value">' . $createTime . ' (创建)</span>
                        </div>';
                }
            }
            
            $html .= '
                </div>
            </div>
        </div>';
        }

        $html .= '
    </div>
    
    <script>
        // 自动打印（可选）
        // window.onload = function() {
        //     setTimeout(function() {
        //         window.print();
        //     }, 1000);
        // };
    </script>
</body>
</html>';

        return $html;
    }

    /**
     * 生成二维码ZIP包
     */
    private function generateQrCodeZip($traceCodes)
    {
        $tempDir = ROOT_PATH . 'public' . DS . 'temp' . DS . 'qrcodes' . DS;
        if (!is_dir($tempDir)) {
            mkdir($tempDir, 0755, true);
        }

        $zipFile = $tempDir . 'trace_codes_' . time() . '.zip';
        $zip = new \ZipArchive();
        
        if ($zip->open($zipFile, \ZipArchive::CREATE) !== TRUE) {
            return false;
        }

        foreach ($traceCodes as $trace) {
            // 生成二维码内容（追溯页面URL）
            $traceUrl = ConfigModel::getSiteDomain() . '/trace.html?id=' . $trace->trace_code;
            
            // 获取追溯码详细信息（包含关联数据）
            $traceData = $this->getTraceDetailData($trace->id);
            
            // 强制重新生成二维码文件（专门用于下载）
            $qrCodeFile = $this->generateDownloadQrCodeImage($traceUrl, $trace->trace_code, $traceData);
            \think\Log::info('下载时强制重新生成二维码文件: ' . $trace->trace_code);
            
            if ($qrCodeFile && file_exists($qrCodeFile)) {
                // 生成包含产品名称和员工姓名的文件名
                $fileName = $this->generateFileName($traceData);
                $zip->addFile($qrCodeFile, $fileName . '.png');
            }
        }

        $zip->close();
        return $zipFile;
    }

    /**
     * 生成下载用的二维码图片（包含产品信息的完整标签）
     */
    private function generateDownloadQrCodeImage($content, $filename, $traceData)
    {
        $qrCodeDir = ROOT_PATH . 'public' . DS . 'temp' . DS . 'qrcodes' . DS;
        if (!is_dir($qrCodeDir)) {
            mkdir($qrCodeDir, 0755, true);
        }
        
        $qrCodeFile = $qrCodeDir . 'download_' . $filename . '.png';
        
        // 强制重新生成，清除缓存
        if (file_exists($qrCodeFile)) {
            @unlink($qrCodeFile);
            \think\Log::info('删除旧的下载二维码文件，强制重新生成: ' . $filename);
        }
        
        try {
            // 使用endroid/qr-code库生成二维码
            $qrCode = \Endroid\QrCode\QrCode::create($content)
                ->setSize(300)
                ->setMargin(10);
            
            // 创建PNG写入器
            $writer = new \Endroid\QrCode\Writer\PngWriter();
            
            // 生成二维码图片数据
            $result = $writer->write($qrCode);
            $qrCodeImageData = $result->getString();
            
            // 创建包含产品信息的完整标签（专门用于下载）
            $this->createCompleteQrCodeLabel($qrCodeFile, $qrCodeImageData, $traceData);
            
            \think\Log::info('生成新的下载二维码文件: ' . $filename);
            return $qrCodeFile;
            
        } catch (\Exception $e) {
            // 如果本地库失败，记录错误并创建占位符图片
            \think\Log::error('下载二维码生成失败: ' . $e->getMessage());
            $this->createPlaceholderQrCode($qrCodeFile, $content, $traceData);
            return $qrCodeFile;
        }
    }

    /**
     * 获取二维码文件路径
     */
    private function getQrCodeFilePath($filename)
    {
        $qrCodeDir = ROOT_PATH . 'public' . DS . 'temp' . DS . 'qrcodes' . DS;
        if (!is_dir($qrCodeDir)) {
            mkdir($qrCodeDir, 0755, true);
        }
        return $qrCodeDir . $filename . '.png';
    }
    
    /**
     * 创建完整的二维码标签（左侧二维码，右侧产品信息）
     */
    private function createCompleteQrCodeLabel($filepath, $qrCodeImageData, $traceData)
    {
        // 创建标签尺寸 (600 x 300 pixels) - 减少高度，去掉空白
        $width = 600;
        $height = 300;
        
        // 创建图片
        $image = imagecreate($width, $height);
        
        // 设置颜色
        $white = imagecolorallocate($image, 255, 255, 255);
        $black = imagecolorallocate($image, 0, 0, 0);
        $lightGray = imagecolorallocate($image, 248, 250, 252);
        $borderGray = imagecolorallocate($image, 226, 232, 240);
        $textGray = imagecolorallocate($image, 107, 114, 128);
        $darkText = imagecolorallocate($image, 31, 41, 55);
        
        // 填充白色背景
        imagefill($image, 0, 0, $white);
        
        // 绘制边框
        imagerectangle($image, 0, 0, $width - 1, $height - 1, $borderGray);
        
        // 左侧二维码区域
        $qrAreaX = 20;
        $qrAreaY = 20;
        $qrAreaWidth = 200;
        $qrAreaHeight = 200;
        
        // 二维码区域背景
        imagefilledrectangle($image, $qrAreaX, $qrAreaY, $qrAreaX + $qrAreaWidth, $qrAreaY + $qrAreaHeight, $lightGray);
        imagerectangle($image, $qrAreaX, $qrAreaY, $qrAreaX + $qrAreaWidth, $qrAreaY + $qrAreaHeight, $borderGray);
        
        // 将二维码图片嵌入到左侧区域
        $qrImage = imagecreatefromstring($qrCodeImageData);
        if ($qrImage) {
            $qrWidth = imagesx($qrImage);
            $qrHeight = imagesy($qrImage);
            
            // 计算缩放比例，确保二维码适合区域
            $scale = min($qrAreaWidth / $qrWidth, $qrAreaHeight / $qrHeight);
            $newWidth = $qrWidth * $scale;
            $newHeight = $qrHeight * $scale;
            
            // 居中放置二维码
            $qrX = $qrAreaX + ($qrAreaWidth - $newWidth) / 2;
            $qrY = $qrAreaY + ($qrAreaHeight - $newHeight) / 2;
            
            imagecopyresampled($image, $qrImage, $qrX, $qrY, 0, 0, $newWidth, $newHeight, $qrWidth, $qrHeight);
            imagedestroy($qrImage);
        }
        
        // 在二维码下方添加追溯码
        $traceCode = $traceData['trace_code'] ?? '';
        if ($traceCode) {
            $traceCodeX = $qrAreaX + ($qrAreaWidth - strlen($traceCode) * 6) / 2;
            $traceCodeY = $qrAreaY + $qrAreaHeight + 15;
            imagestring($image, 2, $traceCodeX, $traceCodeY, $traceCode, $black);
        }
        
        // 右侧产品信息区域
        $infoAreaX = $qrAreaX + $qrAreaWidth + 20;
        $infoAreaY = 20;
        $infoAreaWidth = $width - $infoAreaX - 20;
        $infoAreaHeight = 200;
        
        // 产品信息区域背景
        imagefilledrectangle($image, $infoAreaX, $infoAreaY, $infoAreaX + $infoAreaWidth, $infoAreaY + $infoAreaHeight, $white);
        imagerectangle($image, $infoAreaX, $infoAreaY, $infoAreaX + $infoAreaWidth, $infoAreaY + $infoAreaHeight, $borderGray);
        
        // 标题
        $title = "产品信息";
        $titleX = $infoAreaX + 10;
        $titleY = $infoAreaY + 15;
        
        // 尝试使用TTF字体显示中文，如果没有字体文件则使用英文
        $fontFile = ROOT_PATH . 'public' . DS . 'assets' . DS . 'fonts' . DS . 'simhei.ttf';
        if (file_exists($fontFile)) {
            // 使用TTF字体显示中文
            imagettftext($image, 12, 0, $titleX, $titleY + 12, $darkText, $fontFile, $title);
        } else {
            // 没有字体文件时使用英文
            imagestring($image, 3, $titleX, $titleY, "Product Info", $darkText);
        }
        
        // 产品信息内容
        $infoY = $titleY + 30;
        $lineHeight = 18;
        
        $infoItems = [
            '产品' => $traceData['product_name'] ?? '',
            '型号' => $traceData['model_name'] ?? '',
            '订单名称' => $traceData['order_name'] ?? '',
            '工序' => $traceData['process_name'] ?? '',
            '员工' => $traceData['worker_name'] ?? '',
            '时间' => isset($traceData['audit_time']) ? date('Y-m-d', $traceData['audit_time']) : 
                     (isset($traceData['report_audit_time']) ? date('Y-m-d', $traceData['report_audit_time']) : ''),
            '布料规格' => $traceData['fabric_color'] ?? ''
        ];
        
        foreach ($infoItems as $label => $value) {
            if (!empty($value)) {
                $labelText = $label . ": " . $value;
                
                if (file_exists($fontFile)) {
                    // 使用TTF字体显示中文
                    imagettftext($image, 10, 0, $titleX, $infoY + 10, $darkText, $fontFile, $labelText);
                } else {
                    // 没有字体文件时使用英文
                    $englishText = "Info: " . $value;
                    imagestring($image, 2, $titleX, $infoY, $englishText, $darkText);
                }
                
                $infoY += $lineHeight;
            }
        }
        
        // 保存图片
        imagepng($image, $filepath);
        imagedestroy($image);
    }
    


    /**
     * 生成二维码图片（带缓存）
     */
    private function generateQrCodeImage($content, $filename, $traceData = null)
    {
        $qrCodeDir = ROOT_PATH . 'public' . DS . 'temp' . DS . 'qrcodes' . DS;
        if (!is_dir($qrCodeDir)) {
            mkdir($qrCodeDir, 0755, true);
        }
        
        $qrCodeFile = $qrCodeDir . $filename . '.png';
        
        // 强制重新生成，清除缓存
        if (file_exists($qrCodeFile)) {
            @unlink($qrCodeFile);
            \think\Log::info('删除旧的二维码文件，强制重新生成: ' . $filename);
        }
        
        try {
            // 使用endroid/qr-code库生成二维码
            $qrCode = \Endroid\QrCode\QrCode::create($content)
                ->setSize(300)
                ->setMargin(10);
            
            // 创建PNG写入器
            $writer = new \Endroid\QrCode\Writer\PngWriter();
            
            // 生成二维码图片数据
            $result = $writer->write($qrCode);
            $qrCodeImageData = $result->getString();
            
            // 直接保存二维码图片（用于打印页面显示）
            file_put_contents($qrCodeFile, $qrCodeImageData);
            
            // 云端备份（可选）
            $this->backupQrCodeToCloud($qrCodeImageData, $filename);
            
            \think\Log::info('生成新的二维码文件: ' . $filename);
            return $qrCodeFile;
            
        } catch (\Exception $e) {
            // 如果本地库失败，记录错误并创建占位符图片
            \think\Log::error('二维码生成失败: ' . $e->getMessage());
            $this->createPlaceholderQrCode($qrCodeFile, $content, $traceData);
            return $qrCodeFile;
        }
    }

    /**
     * 创建美化二维码图片（将真实二维码嵌入到美化模板中）
     */
    private function createBeautifiedQrCode($filepath, $qrCodeImageData, $content, $traceData = null)
    {
        // 创建A4尺寸的图片 (2480 x 3508 pixels at 300 DPI)
        $width = 800;
        $height = 1000;
        
        // 创建图片
        $image = imagecreate($width, $height);
        
        // 设置颜色
        $white = imagecolorallocate($image, 255, 255, 255);
        $black = imagecolorallocate($image, 0, 0, 0);
        $gray = imagecolorallocate($image, 128, 128, 128);
        $blue = imagecolorallocate($image, 59, 130, 246); // 蓝色主题
        $green = imagecolorallocate($image, 16, 185, 129); // 绿色主题
        $orange = imagecolorallocate($image, 249, 115, 22); // 橙色主题
        $purple = imagecolorallocate($image, 139, 92, 246); // 紫色主题
        $lightGray = imagecolorallocate($image, 243, 244, 246); // 浅灰色背景
        
        // 填充白色背景
        imagefill($image, 0, 0, $white);
        
        // 绘制顶部装饰条
        imagefilledrectangle($image, 0, 0, $width, 60, $blue);
        
        // 绘制标题
        $title = "产品追溯码";
        $fontSize = 5;
        $titleWidth = imagefontwidth($fontSize) * strlen($title);
        $titleX = intval(($width - $titleWidth) / 2);
        $titleY = 20;
        imagestring($image, $fontSize, $titleX, $titleY, $title, $white);
        
        // 绘制二维码区域背景
        $qrAreaX = 50;
        $qrAreaY = 80;
        $qrAreaWidth = 300;
        $qrAreaHeight = 300;
        imagefilledrectangle($image, $qrAreaX, $qrAreaY, $qrAreaX + $qrAreaWidth, $qrAreaY + $qrAreaHeight, $lightGray);
        imagerectangle($image, $qrAreaX, $qrAreaY, $qrAreaX + $qrAreaWidth, $qrAreaY + $qrAreaHeight, $blue);
        
        // 将真实二维码图片嵌入到区域中心
        $qrImage = imagecreatefromstring($qrCodeImageData);
        if ($qrImage) {
            $qrImageWidth = imagesx($qrImage);
            $qrImageHeight = imagesy($qrImage);
            
            // 计算缩放比例，确保二维码适合区域
            $scale = min($qrAreaWidth / $qrImageWidth, $qrAreaHeight / $qrImageHeight) * 0.8; // 留一些边距
            $newWidth = intval($qrImageWidth * $scale);
            $newHeight = intval($qrImageHeight * $scale);
            
            // 计算居中位置
            $qrX = intval($qrAreaX + ($qrAreaWidth - $newWidth) / 2);
            $qrY = intval($qrAreaY + ($qrAreaHeight - $newHeight) / 2);
            
            // 复制并缩放二维码图片
            imagecopyresampled($image, $qrImage, $qrX, $qrY, 0, 0, $newWidth, $newHeight, $qrImageWidth, $qrImageHeight);
            imagedestroy($qrImage);
        }
        
        // 绘制追溯码
        if ($traceData && isset($traceData['trace_code'])) {
            $traceCode = "追溯码: " . $traceData['trace_code'];
            $traceWidth = imagefontwidth($fontSize) * strlen($traceCode);
            $traceX = intval(($width - $traceWidth) / 2);
            $traceY = $qrAreaY + $qrAreaHeight + 30;
            imagestring($image, $fontSize, $traceX, $traceY, $traceCode, $black);
        }
        
        // 绘制产品信息区域
        $infoStartY = $traceY + 50;
        $infoX = 50;
        $infoWidth = $width - 100;
        $lineHeight = 25;
        
        // 信息区域背景
        imagefilledrectangle($image, $infoX, $infoStartY, $infoX + $infoWidth, $infoStartY + 200, $lightGray);
        imagerectangle($image, $infoX, $infoStartY, $infoX + $infoWidth, $infoStartY + 200, $blue);
        
        // 信息区域标题
        $infoTitle = "产品信息";
        $infoTitleWidth = imagefontwidth($fontSize) * strlen($infoTitle);
        $infoTitleX = $infoX + 10;
        $infoTitleY = $infoStartY + 10;
        imagestring($image, $fontSize, $infoTitleX, $infoTitleY, $infoTitle, $blue);
        
        // 绘制产品信息
        $currentY = $infoStartY + 40;
        if ($traceData) {
            $infoLines = [];
            
            if (isset($traceData['product_name']) && $traceData['product_name']) {
                $infoLines[] = ["产品", $traceData['product_name'], $green];
            }
            
            if (isset($traceData['model_name']) && $traceData['model_name']) {
                $infoLines[] = ["型号", $traceData['model_name'], $orange];
            }
            
            if (isset($traceData['order_name']) && $traceData['order_name']) {
                $infoLines[] = ["订单名称", $traceData['order_name'], $purple];
            }
            
            if (isset($traceData['process_name']) && $traceData['process_name']) {
                $infoLines[] = ["工序", $traceData['process_name'], $blue];
            }
            
            if (isset($traceData['worker_name']) && $traceData['worker_name']) {
                $infoLines[] = ["员工", $traceData['worker_name'], $green];
            }
            
            if (isset($traceData['audit_time']) && $traceData['audit_time']) {
                $auditTime = date('Y-m-d', $traceData['audit_time']);
                $infoLines[] = ["时间", $auditTime, $orange];
            } elseif (isset($traceData['report_audit_time']) && $traceData['report_audit_time']) {
                $auditTime = date('Y-m-d', $traceData['report_audit_time']);
                $infoLines[] = ["时间", $auditTime, $orange];
            }
            
            if (isset($traceData['fabric_color']) && $traceData['fabric_color']) {
                $infoLines[] = ["布料规格", $traceData['fabric_color'], $blue];
            }
            
            // 绘制信息行
            foreach ($infoLines as $line) {
                $label = $line[0] . ": ";
                $value = $line[1];
                $color = $line[2];
                
                // 绘制标签
                imagestring($image, $fontSize, $infoX + 10, $currentY, $label, $black);
                
                // 绘制值
                $labelWidth = imagefontwidth($fontSize) * strlen($label);
                imagestring($image, $fontSize, $infoX + 10 + $labelWidth, $currentY, $value, $color);
                
                $currentY += $lineHeight;
            }
        }
        
        // 绘制底部说明
        $bottomY = $infoStartY + 220;
        $note = "扫描二维码查看详细信息";
        $noteWidth = imagefontwidth($fontSize) * strlen($note);
        $noteX = intval(($width - $noteWidth) / 2);
        imagestring($image, $fontSize, $noteX, $bottomY, $note, $gray);
        
        // 绘制URL（截取显示）
        $urlY = $bottomY + 20;
        $displayUrl = "URL: " . substr($content, 0, 50) . "...";
        $urlWidth = imagefontwidth($fontSize) * strlen($displayUrl);
        $urlX = intval(($width - $urlWidth) / 2);
        imagestring($image, $fontSize, $urlX, $urlY, $displayUrl, $gray);
        
        // 保存图片
        imagepng($image, $filepath);
        imagedestroy($image);
    }
    
    /**
     * 创建美化二维码图片
     */
    private function createPlaceholderQrCode($filepath, $content, $traceData = null)
    {
        // 创建A4尺寸的图片 (2480 x 3508 pixels at 300 DPI)
        $width = 800;
        $height = 1000;
        
        // 创建图片
        $image = imagecreate($width, $height);
        
        // 设置颜色
        $white = imagecolorallocate($image, 255, 255, 255);
        $black = imagecolorallocate($image, 0, 0, 0);
        $gray = imagecolorallocate($image, 128, 128, 128);
        $blue = imagecolorallocate($image, 59, 130, 246); // 蓝色主题
        $green = imagecolorallocate($image, 16, 185, 129); // 绿色主题
        $orange = imagecolorallocate($image, 249, 115, 22); // 橙色主题
        $purple = imagecolorallocate($image, 139, 92, 246); // 紫色主题
        $lightGray = imagecolorallocate($image, 243, 244, 246); // 浅灰色背景
        
        // 填充白色背景
        imagefill($image, 0, 0, $white);
        
        // 绘制顶部装饰条
        imagefilledrectangle($image, 0, 0, $width, 60, $blue);
        
        // 绘制标题
        $title = "产品追溯码";
        $fontSize = 5;
        $titleWidth = imagefontwidth($fontSize) * strlen($title);
        $titleX = ($width - $titleWidth) / 2;
        $titleY = 20;
        imagestring($image, $fontSize, $titleX, $titleY, $title, $white);
        
        // 绘制二维码区域背景
        $qrAreaX = 50;
        $qrAreaY = 80;
        $qrAreaWidth = 300;
        $qrAreaHeight = 300;
        imagefilledrectangle($image, $qrAreaX, $qrAreaY, $qrAreaX + $qrAreaWidth, $qrAreaY + $qrAreaHeight, $lightGray);
        imagerectangle($image, $qrAreaX, $qrAreaY, $qrAreaX + $qrAreaWidth, $qrAreaY + $qrAreaHeight, $blue);
        
        // 在二维码区域中心绘制占位符
        $qrPlaceholderSize = 200;
        $qrPlaceholderX = intval($qrAreaX + ($qrAreaWidth - $qrPlaceholderSize) / 2);
        $qrPlaceholderY = intval($qrAreaY + ($qrAreaHeight - $qrPlaceholderSize) / 2);
        imagefilledrectangle($image, $qrPlaceholderX, $qrPlaceholderY, $qrPlaceholderX + $qrPlaceholderSize, $qrPlaceholderY + $qrPlaceholderSize, $white);
        imagerectangle($image, $qrPlaceholderX, $qrPlaceholderY, $qrPlaceholderX + $qrPlaceholderSize, $qrPlaceholderY + $qrPlaceholderSize, $blue);
        
        // 在二维码占位符中心绘制文字
        $qrText = "QR Code";
        $qrTextWidth = imagefontwidth($fontSize) * strlen($qrText);
        $qrTextX = intval($qrPlaceholderX + ($qrPlaceholderSize - $qrTextWidth) / 2);
        $qrTextY = intval($qrPlaceholderY + ($qrPlaceholderSize - imagefontheight($fontSize)) / 2);
        imagestring($image, $fontSize, $qrTextX, $qrTextY, $qrText, $blue);
        
        // 绘制追溯码
        if ($traceData && isset($traceData['trace_code'])) {
            $traceCode = "追溯码: " . $traceData['trace_code'];
            $traceWidth = imagefontwidth($fontSize) * strlen($traceCode);
            $traceX = ($width - $traceWidth) / 2;
            $traceY = $qrAreaY + $qrAreaHeight + 30;
            imagestring($image, $fontSize, $traceX, $traceY, $traceCode, $black);
        }
        
        // 绘制产品信息区域
        $infoStartY = $traceY + 50;
        $infoX = 50;
        $infoWidth = $width - 100;
        $lineHeight = 25;
        
        // 信息区域背景
        imagefilledrectangle($image, $infoX, $infoStartY, $infoX + $infoWidth, $infoStartY + 200, $lightGray);
        imagerectangle($image, $infoX, $infoStartY, $infoX + $infoWidth, $infoStartY + 200, $blue);
        
        // 信息区域标题
        $infoTitle = "产品信息";
        $infoTitleWidth = imagefontwidth($fontSize) * strlen($infoTitle);
        $infoTitleX = $infoX + 10;
        $infoTitleY = $infoStartY + 10;
        imagestring($image, $fontSize, $infoTitleX, $infoTitleY, $infoTitle, $blue);
        
        // 绘制产品信息
        $currentY = $infoStartY + 40;
        if ($traceData) {
            $infoLines = [];
            
            if (isset($traceData['product_name']) && $traceData['product_name']) {
                $infoLines[] = ["产品名称", $traceData['product_name'], $green];
            }
            
            if (isset($traceData['model_name']) && $traceData['model_name']) {
                $infoLines[] = ["产品型号", $traceData['model_name'], $orange];
            }
            
            if (isset($traceData['order_no']) && $traceData['order_no']) {
                $infoLines[] = ["订单号", $traceData['order_no'], $purple];
            }
            
            if (isset($traceData['process_name']) && $traceData['process_name']) {
                $infoLines[] = ["工序", $traceData['process_name'], $blue];
            }
            
            if (isset($traceData['worker_name']) && $traceData['worker_name']) {
                $infoLines[] = ["员工", $traceData['worker_name'], $green];
            }
            
            if (isset($traceData['audit_time']) && $traceData['audit_time']) {
                $auditTime = date('Y-m-d H:i', $traceData['audit_time']);
                $infoLines[] = ["审核时间", $auditTime, $orange];
            }
            
            // 绘制信息行
            foreach ($infoLines as $line) {
                $label = $line[0] . ": ";
                $value = $line[1];
                $color = $line[2];
                
                // 绘制标签
                imagestring($image, $fontSize, $infoX + 10, $currentY, $label, $black);
                
                // 绘制值
                $labelWidth = imagefontwidth($fontSize) * strlen($label);
                imagestring($image, $fontSize, $infoX + 10 + $labelWidth, $currentY, $value, $color);
                
                $currentY += $lineHeight;
            }
        }
        
        // 绘制底部说明
        $bottomY = $infoStartY + 220;
        $note = "扫描二维码查看详细信息";
        $noteWidth = imagefontwidth($fontSize) * strlen($note);
        $noteX = intval(($width - $noteWidth) / 2);
        imagestring($image, $fontSize, $noteX, $bottomY, $note, $gray);
        
        // 绘制URL（截取显示）
        $urlY = $bottomY + 20;
        $displayUrl = "URL: " . substr($content, 0, 50) . "...";
        $urlWidth = imagefontwidth($fontSize) * strlen($displayUrl);
        $urlX = intval(($width - $urlWidth) / 2);
        imagestring($image, $fontSize, $urlX, $urlY, $displayUrl, $gray);
        
        // 保存图片
        imagepng($image, $filepath);
        imagedestroy($image);
    }

    /**
     * 获取追溯码详细信息
     */
    private function getTraceDetailData($traceId)
    {
        $trace = Db::name('scanwork_trace_codes')
            ->alias('t')
            ->join('fa_scanwork_report r', 't.report_id = r.id')
            ->join('fa_scanwork_allocation a', 'r.allocation_id = a.id')
            ->join('fa_scanwork_order o', 'a.order_id = o.id')
            ->join('fa_scanwork_model m', 'a.model_id = m.id')
            ->join('fa_scanwork_product p', 'm.product_id = p.id')
            ->join('fa_scanwork_process proc', 'a.process_id = proc.id')
            ->join('fa_user worker', 'r.user_id = worker.id')
            ->join('fa_user auditor', 'r.audit_user_id = auditor.id', 'LEFT')
            ->field('t.*, o.order_no, o.order_name, o.customer_name, m.name as model_name, m.model_code, m.fabric_color, p.name as product_name, proc.name as process_name, worker.nickname as worker_name, auditor.nickname as auditor_name, r.quantity, r.item_nos, r.remark as report_remark, r.audit_time as report_audit_time, r.audit_reason, r.work_hours, r.wage, r.allocation_id, r.createtime, t.audit_time')
            ->where('t.id', $traceId)
            ->find();

        return $trace ? $trace : [];
    }

    /**
     * 生成包含产品信息的文件名
     */
    private function generateFileName($traceData)
    {
        $parts = [];
        
        // 添加追溯码
        $parts[] = $traceData['trace_code'] ?? '';
        
        // 添加产品名称
        if (!empty($traceData['product_name'])) {
            $parts[] = $traceData['product_name'];
        }
        
        // 添加型号
        if (!empty($traceData['model_name'])) {
            $parts[] = $traceData['model_name'];
        }
        
        // 添加工序
        if (!empty($traceData['process_name'])) {
            $parts[] = $traceData['process_name'];
        }
        
        // 添加员工姓名
        if (!empty($traceData['worker_name'])) {
            $parts[] = $traceData['worker_name'];
        }
        
        // 添加审核时间（年月日）
        if (!empty($traceData['report_audit_time'])) {
            $parts[] = date('Ymd', $traceData['report_audit_time']);
        }
        
        // 组合文件名，用下划线分隔
        $fileName = implode('_', array_filter($parts));
        
        // 移除特殊字符，只保留字母、数字、中文和下划线
        $fileName = preg_replace('/[^a-zA-Z0-9\x{4e00}-\x{9fa5}_]/u', '', $fileName);
        
        return $fileName;
    }

    /**
     * 预览追溯页面
     */
    public function preview($id = null)
    {
        $trace = $this->model->find($id);
        if (!$trace) {
            $this->error('追溯码不存在');
        }

        $traceUrl = ConfigModel::getSiteDomain() . '/trace.html?id=' . $trace->trace_code;
        $this->redirect($traceUrl);
    }

    /**
     * 查看报工详情
     */
    public function detail($id = null)
    {
        // 支持通过追溯码或ID查询
        if (is_numeric($id)) {
            $where = 't.id = ' . intval($id);
        } else {
            $where = "t.trace_code = '" . addslashes($id) . "'";
        }

        $trace = $this->model
            ->alias('t')
            ->join('fa_scanwork_report r', 't.report_id = r.id')
            ->join('fa_scanwork_allocation a', 'r.allocation_id = a.id')
            ->join('fa_scanwork_order o', 'a.order_id = o.id')
            ->join('fa_scanwork_model m', 'a.model_id = m.id')
            ->join('fa_scanwork_process p', 'a.process_id = p.id')
            ->join('fa_user worker', 'r.user_id = worker.id', 'LEFT')
            ->join('fa_user auditor', 'r.audit_user_id = auditor.id', 'LEFT')
            ->field('t.*, o.order_no, o.customer_name, m.name as model_name, m.model_code, p.name as process_name, worker.nickname as worker_name, auditor.nickname as auditor_name, r.quantity, r.item_nos, r.remark, r.audit_time as report_audit_time, r.audit_reason, r.work_hours, r.wage, r.allocation_id')
            ->where($where)
            ->find();

        if (!$trace) {
            $this->error('追溯码不存在');
        }

        // 转换为数组
        $trace = $trace->toArray();

        // 处理产品编号，解析JSON数组
        if ($trace && $trace['item_nos']) {
            $itemNos = json_decode($trace['item_nos'], true);
            if (is_array($itemNos)) {
                $trace['item_nos_array'] = $itemNos;
            } else {
                $trace['item_nos_array'] = [$trace['item_nos']];
            }
        } else {
            $trace['item_nos_array'] = [];
        }

        if (!$trace) {
            $this->error('追溯码不存在');
        }

        // 获取每个产品编号的图片和视频
        $trace['item_media'] = [];
        foreach ($trace['item_nos_array'] as $itemNo) {
            $itemMedia = [
                'item_no' => $itemNo,
                'audit_images' => [],
                'audit_videos' => []
            ];

            // 先通过item_no找到对应的item_id
            $productItem = Db::name('scanwork_product_item')
                ->where('item_no', $itemNo)
                ->where('allocation_id', $trace['allocation_id'])
                ->find();

            if ($productItem) {
                // 获取审核图片和视频（都存储在同一个表中）
                $auditFiles = Db::name('scanwork_item_audit_image')
                    ->where('item_id', $productItem['id'])
                    ->where('report_id', $trace['report_id'])
                    ->field('image_url, createtime')
                    ->select();

                // 根据文件扩展名分类图片和视频
                foreach ($auditFiles as $file) {
                    $extension = strtolower(pathinfo($file['image_url'], PATHINFO_EXTENSION));
                    \think\Log::info("处理文件: {$file['image_url']}, 扩展名: {$extension}");
                    if (in_array($extension, ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp'])) {
                        $itemMedia['audit_images'][] = $file;
                        \think\Log::info("分类为图片: {$file['image_url']}");
                    } elseif (in_array($extension, ['mp4', 'avi', 'mov', 'wmv', 'flv'])) {
                        $itemMedia['audit_videos'][] = $file;
                        \think\Log::info("分类为视频: {$file['image_url']}");
                    } else {
                        \think\Log::info("未知文件类型: {$file['image_url']}, 扩展名: {$extension}");
                    }
                }
            }

            $trace['item_media'][] = $itemMedia;
        }

        // 获取普通报工图片（不按产品编号分组）
        $trace['report_images'] = Db::name('scanwork_report_image')
            ->where('report_id', $trace['report_id'])
            ->field('image_url, createtime')
            ->select();

        $this->view->assign('trace', $trace);
        return $this->view->fetch();
    }

    /**
     * 获取追溯信息（用于前端页面）
     */
    public function getTraceInfo()
    {
        $traceCode = $this->request->get('id');
        
        if (!$traceCode) {
            return json(['code' => 0, 'msg' => '缺少追溯码参数']);
        }
        
        // 支持通过追溯码或ID查询
        if (is_numeric($traceCode)) {
            $where = 't.id = ' . intval($traceCode);
        } else {
            $where = "t.trace_code = '" . addslashes($traceCode) . "'";
        }

        $trace = $this->model
        ->alias('t')
        ->join('fa_scanwork_report r', 't.report_id = r.id')
        ->join('fa_scanwork_allocation a', 'r.allocation_id = a.id')
        ->join('fa_scanwork_order o', 'a.order_id = o.id')
        ->join('fa_scanwork_model m', 'a.model_id = m.id')
        ->join('fa_scanwork_process p', 'a.process_id = p.id')
        ->join('fa_user worker', 'r.user_id = worker.id', 'LEFT')
        ->join('fa_user auditor', 'r.audit_user_id = auditor.id', 'LEFT')
            ->field('t.*, o.order_no, o.customer_name, m.name as model_name, m.model_code, p.name as process_name, worker.nickname as worker_name, auditor.nickname as auditor_name, r.quantity, r.item_nos, r.remark, r.audit_time as report_audit_time, r.audit_reason, r.work_hours, r.wage, r.allocation_id')
            ->where($where)
            ->find();

        if (!$trace) {
            return json(['code' => 0, 'msg' => '追溯码不存在或已失效']);
        }

        // 转换为数组
        $trace = $trace->toArray();

        // 处理产品编号，解析JSON数组
        if ($trace && $trace['item_nos']) {
            $itemNos = json_decode($trace['item_nos'], true);
            if (is_array($itemNos)) {
                $trace['item_nos_array'] = $itemNos;
            } else {
                $trace['item_nos_array'] = [$trace['item_nos']];
            }
        } else {
            $trace['item_nos_array'] = [];
        }

        // 获取每个产品编号的图片和视频
        $trace['item_media'] = [];
        foreach ($trace['item_nos_array'] as $itemNo) {
            $itemMedia = [
                'item_no' => $itemNo,
                'audit_images' => [],
                'audit_videos' => []
            ];

            // 先通过item_no找到对应的item_id
            $productItem = Db::name('scanwork_product_item')
                ->where('item_no', $itemNo)
                ->where('allocation_id', $trace['allocation_id'])
                ->find();

            if ($productItem) {
                // 获取审核图片和视频（都存储在同一个表中）
                $auditFiles = Db::name('scanwork_item_audit_image')
                    ->where('item_id', $productItem['id'])
                    ->where('report_id', $trace['report_id'])
                    ->field('image_url, createtime')
                    ->select();

                // 根据文件扩展名分类图片和视频
                foreach ($auditFiles as $file) {
                    $extension = strtolower(pathinfo($file['image_url'], PATHINFO_EXTENSION));
                    \think\Log::info("处理文件: {$file['image_url']}, 扩展名: {$extension}");
                    if (in_array($extension, ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp'])) {
                        $itemMedia['audit_images'][] = $file;
                        \think\Log::info("分类为图片: {$file['image_url']}");
                    } elseif (in_array($extension, ['mp4', 'avi', 'mov', 'wmv', 'flv'])) {
                        $itemMedia['audit_videos'][] = $file;
                        \think\Log::info("分类为视频: {$file['image_url']}");
                    } else {
                        \think\Log::info("未知文件类型: {$file['image_url']}, 扩展名: {$extension}");
                    }
                }
            }

            $trace['item_media'][] = $itemMedia;
        }

        // 获取普通报工图片（不按产品编号分组）
        $trace['report_images'] = Db::name('scanwork_report_image')
            ->where('report_id', $trace['report_id'])
            ->field('image_url, createtime')
            ->select();
        
        return json(['code' => 1, 'msg' => '获取成功', 'data' => $trace]);
    }
    
    /**
     * 云端备份二维码（备用方案）
     */
    private function backupQrCodeToCloud($qrCodeData, $filename)
    {
        try {
            // 使用ScanworkCloudService进行云端备份
            $cloudService = new \app\common\service\ScanworkCloudService();
            
            // 创建临时文件
            $tempDir = ROOT_PATH . 'public' . DS . 'temp' . DS . 'qrcodes' . DS;
            if (!is_dir($tempDir)) {
                mkdir($tempDir, 0755, true);
            }
            
            $tempFile = $tempDir . 'temp_' . $filename . '.png';
            file_put_contents($tempFile, $qrCodeData);
            
            // 构建文件数组
            $file = [
                'name' => $filename . '.png',
                'type' => 'image/png',
                'tmp_name' => $tempFile,
                'error' => 0,
                'size' => filesize($tempFile)
            ];
            
            // 上传到云端
            $result = $cloudService->uploadReportImage($file, 'scanwork', 'qrcode');
            
            // 删除临时文件
            @unlink($tempFile);
            
            if ($result['success']) {
                \think\Log::info('二维码云端备份成功: ' . $result['url']);
                return $result['url'];
            } else {
                \think\Log::error('云端备份二维码失败: ' . $result['message']);
                return false;
            }
            
        } catch (\Exception $e) {
            \think\Log::error('云端备份二维码失败: ' . $e->getMessage());
            return false;
        }
    }
    
    /**
     * 清理过期的二维码文件
     */
    public function cleanExpiredQrCodes()
    {
        $qrCodeDir = ROOT_PATH . 'public' . DS . 'temp' . DS . 'qrcodes' . DS;
        if (!is_dir($qrCodeDir)) {
            return ['success' => true, 'message' => '二维码目录不存在'];
        }
        
        $currentTime = time();
        $expireTime = 7 * 24 * 3600; // 7天
        $deletedCount = 0;
        $totalSize = 0;
        
        try {
            $files = glob($qrCodeDir . '*.png');
            foreach ($files as $file) {
                $fileTime = filemtime($file);
                if (($currentTime - $fileTime) > $expireTime) {
                    $fileSize = filesize($file);
                    if (@unlink($file)) {
                        $deletedCount++;
                        $totalSize += $fileSize;
                        \think\Log::info('清理过期二维码文件: ' . basename($file));
                    }
                }
            }
            
            $message = "清理完成：删除 {$deletedCount} 个过期文件，释放 " . round($totalSize / 1024, 2) . " KB 空间";
            \think\Log::info($message);
            
            return ['success' => true, 'message' => $message];
            
        } catch (\Exception $e) {
            $error = '清理过期二维码文件失败: ' . $e->getMessage();
            \think\Log::error($error);
            return ['success' => false, 'message' => $error];
        }
    }
    
    /**
     * 全新的下载二维码标签创建方法 - 完全独立，不和现有方法有任何关联
     */
    private function buildDownloadQrCodeLabel($filepath, $qrCodeImageData, $traceData)
    {
        // 创建标签尺寸 (600 x 300 pixels)
        $width = 600;
        $height = 300;
        
        // 创建图片
        $image = imagecreate($width, $height);
        
        // 设置颜色 - 全部使用黑色系，更实用
        $white = imagecolorallocate($image, 255, 255, 255);
        $black = imagecolorallocate($image, 0, 0, 0);
        $borderGray = imagecolorallocate($image, 200, 200, 200);
        $darkText = imagecolorallocate($image, 31, 41, 55);
        
        // 填充纯白色背景
        imagefill($image, 0, 0, $white);
        
        // 绘制细边框
        imagerectangle($image, 0, 0, $width - 1, $height - 1, $borderGray);
        
        // 左侧二维码区域
        $qrAreaX = 20;
        $qrAreaY = 20;
        $qrAreaWidth = 200;
        $qrAreaHeight = 200;
        
        // 二维码区域 - 只保留细边框，去掉背景
        imagerectangle($image, $qrAreaX, $qrAreaY, $qrAreaX + $qrAreaWidth, $qrAreaY + $qrAreaHeight, $black);
        
        // 将二维码图片嵌入到左侧区域
        $qrImage = imagecreatefromstring($qrCodeImageData);
        if ($qrImage) {
            $qrWidth = imagesx($qrImage);
            $qrHeight = imagesy($qrImage);
            
            // 计算缩放比例，确保二维码适合区域
            $scale = min($qrAreaWidth / $qrWidth, $qrAreaHeight / $qrHeight);
            $newWidth = $qrWidth * $scale;
            $newHeight = $qrHeight * $scale;
            
            // 居中放置二维码
            $qrX = $qrAreaX + ($qrAreaWidth - $newWidth) / 2;
            $qrY = $qrAreaY + ($qrAreaHeight - $newHeight) / 2;
            
            imagecopyresampled($image, $qrImage, $qrX, $qrY, 0, 0, $newWidth, $newHeight, $qrWidth, $qrHeight);
            imagedestroy($qrImage);
        }
        
        // 在二维码下方添加追溯码 - 使用黑色
        $traceCode = $traceData['trace_code'] ?? '';
        if ($traceCode) {
            $traceCodeX = $qrAreaX + ($qrAreaWidth - strlen($traceCode) * 6) / 2;
            $traceCodeY = $qrAreaY + $qrAreaHeight + 15;
            // 使用黑色文字
            imagestring($image, 2, $traceCodeX, $traceCodeY, $traceCode, $black);
        }
        
        // 右侧产品信息区域 - 完全去掉背景，保持简洁
        $infoAreaX = $qrAreaX + $qrAreaWidth + 30; // 增加间距
        $infoAreaY = 25;
        $infoAreaWidth = $width - $infoAreaX - 20;
        
        // 标题 - 使用黑色
        $title = "产品信息";
        $titleX = $infoAreaX;
        $titleY = $infoAreaY;
        
        // 尝试多个字体文件路径，确保能找到可用的字体
        $fontFiles = [
            ROOT_PATH . 'public' . DS . 'assets' . DS . 'fonts' . DS . 'SourceHanSerifCN-Regular.otf',
            ROOT_PATH . 'public' . DS . 'assets' . DS . 'fonts' . DS . 'SourceHanSansK-Regular.ttf',
            ROOT_PATH . 'public' . DS . 'assets' . DS . 'fonts' . DS . 'captcha.ttf',
            ROOT_PATH . 'public' . DS . 'assets' . DS . 'fonts' . DS . 'simhei.ttf',
            ROOT_PATH . 'public' . DS . 'assets' . DS . 'fonts' . DS . 'simsun.ttc',
            ROOT_PATH . 'public' . DS . 'assets' . DS . 'fonts' . DS . 'msyh.ttc',
            '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf',
            '/System/Library/Fonts/Arial.ttf'
        ];
        
        $fontFile = null;
        foreach ($fontFiles as $font) {
            if (file_exists($font)) {
                $fontFile = $font;
                break;
            }
        }
        
        if ($fontFile) {
            // 使用TTF字体显示中文标题（黑色）
            imagettftext($image, 14, 0, $titleX, $titleY + 14, $black, $fontFile, $title);
        } else {
            imagestring($image, 3, $titleX, $titleY, "Product Info", $black);
        }
        
        // 产品信息内容 - 完全去掉背景，使用简洁的布局
        $infoY = $titleY + 25; // 标题下方留更多空间
        $lineHeight = 25; // 增加行高，更易读
        $labelWidth = 70; // 标签固定宽度
        
        $infoItems = [
            '产品' => $traceData['product_name'] ?? '',
            '型号' => $traceData['model_name'] ?? '',
            '订单名称' => $traceData['order_name'] ?? '',
            '工序' => $traceData['process_name'] ?? '',
            '员工' => $traceData['worker_name'] ?? '',
            '时间' => isset($traceData['audit_time']) ? date('Y-m-d', $traceData['audit_time']) : 
                     (isset($traceData['report_audit_time']) ? date('Y-m-d', $traceData['report_audit_time']) : ''),
            '布料规格' => $traceData['fabric_color'] ?? ''
        ];
        
        foreach ($infoItems as $label => $value) {
            if (!empty($value)) {
                // 标签 - 使用黑色文字
                $labelX = $infoAreaX;
                $labelY = $infoY;
                
                if ($fontFile) {
                    imagettftext($image, 10, 0, $labelX, $labelY + 10, $black, $fontFile, $label . ':');
                } else {
                    $englishLabels = [
                        '产品' => 'Product',
                        '型号' => 'Model', 
                        '订单名称' => 'Order',
                        '工序' => 'Process',
                        '员工' => 'Worker',
                        '时间' => 'Time',
                        '布料规格' => 'Fabric'
                    ];
                    $englishLabel = $englishLabels[$label] ?? 'Info';
                    imagestring($image, 2, $labelX, $labelY, $englishLabel . ':', $black);
                }
                
                // 值 - 也使用黑色文字
                $valueX = $labelX + $labelWidth + 5;
                if ($fontFile) {
                    imagettftext($image, 10, 0, $valueX, $infoY + 10, $black, $fontFile, $value);
                } else {
                    imagestring($image, 2, $valueX, $infoY, $value, $black);
                }
                
                $infoY += $lineHeight;
            }
        }
        
        // 保存图片
        imagepng($image, $filepath);
        imagedestroy($image);
    }
    
    /**
     * 全新的下载二维码生成方法 - 完全独立，不和现有方法有任何关联
     */
    private function makeDownloadQrCodeImage($content, $filename, $traceData)
    {
        $qrCodeDir = ROOT_PATH . 'public' . DS . 'temp' . DS . 'qrcodes' . DS;
        if (!is_dir($qrCodeDir)) {
            mkdir($qrCodeDir, 0755, true);
        }
        
        // 使用不同的文件名前缀，避免和打印页面冲突
        $qrCodeFile = $qrCodeDir . 'DOWNLOAD_' . $filename . '.png';
        
        // 强制重新生成，清除缓存
        if (file_exists($qrCodeFile)) {
            @unlink($qrCodeFile);
            \think\Log::info('删除旧的下载二维码文件，强制重新生成: ' . $filename);
        }
        
        try {
            // 使用endroid/qr-code库生成二维码
            $qrCode = \Endroid\QrCode\QrCode::create($content)
                ->setSize(300)
                ->setMargin(10);
            
            // 创建PNG写入器
            $writer = new \Endroid\QrCode\Writer\PngWriter();
            
            // 生成二维码图片数据
            $result = $writer->write($qrCode);
            $qrCodeImageData = $result->getString();
            
            // 创建包含产品信息的完整标签（专门用于下载）
            $this->buildDownloadQrCodeLabel($qrCodeFile, $qrCodeImageData, $traceData);
            
            \think\Log::info('生成新的下载二维码文件: ' . $filename);
            return $qrCodeFile;
            
        } catch (\Exception $e) {
            \think\Log::error('下载二维码生成失败: ' . $e->getMessage());
            return false;
        }
    }
    
    /**
     * 全新的下载入口方法 - 完全独立，不和现有方法有任何关联
     */
    private function downloadQrCodeZip($traceCodes)
    {
        $tempDir = ROOT_PATH . 'public' . DS . 'temp' . DS . 'qrcodes' . DS;
        if (!is_dir($tempDir)) {
            mkdir($tempDir, 0755, true);
        }

        $zipFile = $tempDir . 'DOWNLOAD_trace_codes_' . time() . '.zip';
        $zip = new \ZipArchive();
        
        if ($zip->open($zipFile, \ZipArchive::CREATE) !== TRUE) {
            return false;
        }

        foreach ($traceCodes as $trace) {
            // 生成二维码内容（追溯页面URL）
            $traceUrl = ConfigModel::getSiteDomain() . '/trace.html?id=' . $trace->trace_code;
            
            // 获取追溯码详细信息（包含关联数据）
            $traceData = $this->getTraceDetailData($trace->id);
            
            // 使用全新的下载方法生成二维码文件
            $qrCodeFile = $this->makeDownloadQrCodeImage($traceUrl, $trace->trace_code, $traceData);
            \think\Log::info('下载时使用新方法生成二维码文件: ' . $trace->trace_code);
            
            if ($qrCodeFile && file_exists($qrCodeFile)) {
                // 生成包含产品名称和员工姓名的文件名
                $fileName = $this->generateFileName($traceData);
                $zip->addFile($qrCodeFile, $fileName . '.png');
            }
        }

        $zip->close();
        return $zipFile;
    }
    
    /**
     * 全新的云端下载入口 - 完全独立，不和现有方法有任何关联
     */
    public function downloadQrCodeCloud($ids = null)
    {
        if (!$ids) {
            $this->error('请选择要下载的追溯码');
        }

        $traceIds = explode(',', $ids);
        $traceCodes = $this->model->where('id', 'in', $traceIds)->select();

        if (empty($traceCodes)) {
            $this->error('未找到追溯码记录');
        }

        // 使用云端下载方法，本地不存储任何文件
        $cloudZipUrl = $this->generateCloudQrCodeZip($traceCodes);
        
        if ($cloudZipUrl) {
            // 重定向到云端下载链接
            header('Location: ' . $cloudZipUrl);
            exit;
        } else {
            $this->error('生成云端二维码文件失败');
        }
    }
    
    /**
     * 全新的云端二维码打包方法 - 完全独立，不和现有方法有任何关联
     */
    private function generateCloudQrCodeZip($traceCodes)
    {
        try {
            // 使用ScanworkCloudService进行云端处理
            $cloudService = new \app\common\service\ScanworkCloudService();
            
            // 在本地生成二维码，然后上传到云端
            $cloudQrCodeUrls = [];
            foreach ($traceCodes as $trace) {
                // 生成二维码内容（追溯页面URL）
                $traceUrl = ConfigModel::getSiteDomain() . '/trace_code/trace.html?id=' . $trace->trace_code;
                
                // 获取追溯码详细信息（包含关联数据）
                $traceData = $this->getTraceDetailData($trace->id);
                
                // 在本地生成二维码图片
                $localQrCodeFile = $this->makeDownloadQrCodeImage($traceUrl, $trace->trace_code, $traceData);
                
                if ($localQrCodeFile && file_exists($localQrCodeFile)) {
                    // 上传二维码到云端
                    $uploadResult = $cloudService->uploadQrCodeImage($localQrCodeFile, $trace->trace_code);
                    
                    if ($uploadResult['success']) {
                        $cloudQrCodeUrls[] = $uploadResult['url'];
                        \think\Log::info('二维码上传云端成功: ' . $trace->trace_code);
                        
                        // 删除本地临时文件
                        @unlink($localQrCodeFile);
                    } else {
                        \think\Log::error('二维码上传云端失败: ' . $trace->trace_code . ' - ' . $uploadResult['message']);
                    }
                }
            }
            
            if (empty($cloudQrCodeUrls)) {
                \think\Log::error('没有二维码成功上传到云端');
                return false;
            }
            
            // 调用云端服务打包成zip文件
            $result = $cloudService->createQrCodeZip($cloudQrCodeUrls);
            
            if ($result['success']) {
                \think\Log::info('云端打包二维码文件成功: ' . $result['url']);
                return $result['url'];
            } else {
                \think\Log::error('云端打包二维码文件失败: ' . $result['message']);
                return false;
            }
            
        } catch (\Exception $e) {
            \think\Log::error('云端生成二维码文件异常: ' . $e->getMessage());
            return false;
        }
    }
    
    /**
     * 全新的下载入口 - 完全独立，不和现有方法有任何关联
     */
    public function downloadQrCodeNew($ids = null)
    {
        if (!$ids) {
            $this->error('请选择要下载的追溯码');
        }

        $traceIds = explode(',', $ids);
        $traceCodes = $this->model->where('id', 'in', $traceIds)->select();

        if (empty($traceCodes)) {
            $this->error('未找到追溯码记录');
        }

        // 使用全新的下载方法生成二维码并打包下载
        $zipFile = $this->downloadQrCodeZip($traceCodes);
        
        if ($zipFile && file_exists($zipFile)) {
            header('Content-Type: application/zip');
            header('Content-Disposition: attachment; filename="NEW_DOWNLOAD_trace_codes_' . date('YmdHis') . '.zip"');
            header('Content-Length: ' . filesize($zipFile));
            readfile($zipFile);
            unlink($zipFile); // 删除临时文件
            exit;
        } else {
            $this->error('生成二维码文件失败');
        }
    }
}
